home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-04-14 | 30.8 KB | 1,079 lines | [TEXT/ALFA] |
- ## -*-Tcl-*-
- # ###################################################################
- # Vince's Additions - an extension package for Alpha
- #
- # FILE: "diffMode.tcl"
- # created: 7/3/95 {11:15:02 pm}
- # last update: 14/4/1999 {5:49:33 pm}
- # Author: Vince Darley
- # E-mail: <darley@fas.harvard.edu>
- # mail: Division of Engineering and Applied Sciences, Harvard University
- # Oxford Street, Cambridge MA 02138, USA
- # www: <http://www.fas.harvard.edu/~darley/>
- #
- # improvements Copyright (c) 1997-1998 Vince Darley, all rights reserved
- #
- # Description:
- #
- # Largely re-written Diff mode for Alpha. Still under construction,
- # but already a lot better than the old one. Basic features:
- #
- # A 'Diff' menu, which contains commonly used options.
- #
- # Uses Alpha's 'marks' so that you can patch diffs back and forth
- # between files without losing the correct location in the file.
- # (previously if you modified one of the original windows, all line
- # numbers after that would be incorrect)
- #
- # Limitations:
- #
- # Sadly a lot of Alpha's window manipulation commands only work
- # on the foremost window. This means this code is slowed down a
- # lot because it often has to bring a window to the front before
- # reading/writing into it. There is a flag to setup a hack which
- # helps with this, at the expense of colours in the windows.
- #
- # History:
- #
- # modified by rev reason
- # -------- --- --- -----------
- # 7/3/95 Pete? 1.0 original
- # 3/9/97 VMD 2.0 much improved version
- # 03/23/98 VMD and Jon Guyer 2.0-3.0 various fixes and Voodoo
- # ###################################################################
- ##
-
- # Usage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]
- # [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]
- # [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]
- # [+show-function-line=regexp]
- # [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]
- # [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]
- # [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]
- # [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]
- # [+report-identical-files] [+expand-tabs] [+ignore-all-space]
- # [+file-label=label [+file-label=label]] [+version] path1 path2
-
- alpha::mode Diff 3.0 diffMenu {*.diff *.patch} {diffMenu} {
- alpha::package require -loose AlphaTcl 7.1.6
- addMenu diffMenu •288
- namespace eval compare {}
- menu::insert Utils submenu 0 compare
- menu::insert compare items end "windows" "files…" "directories…"
- hook::register requireOpenWindowsHook [list compare windows] 2
- ensureset DiffSig DIFF
- set Diff::handlers(Diff-mode) Diff::runInsideAlpha
- ensureset Diff::handler Diff-mode
- lunion varPrefs(Files) Diff::handler
- # By default Alpha handles the results of diff internally using
- # its Diff mode. However add-on packages to Alpha can provide
- # alternative Diff handlers.
- newPref var Diff::handler "Diff-mode" global "" Diff::handlers array
- } uninstall {
- file delete "$pkg_file"
- file delete [file join ${HOME} Tools "GNU Diff"]
- } maintainer {
- "Vince Darley" darley@fas.harvard.edu <http://www.fas.harvard.edu/~darley/>
- } help {file "Diff Help"}
-
- array set DiffAppSignatures {
- GnuDiff DIFF
- }
- array set DiffAppScripts {
- GnuDiff {
- {dosc -c $quotedSig -s $flags}
- }
- }
-
- proc diffMenu {} {}
-
- # Generally best to use this setting, but some actions can be a bit
- # slower with it on. Allows you to patch changes back and forth
- # between windows automatically, which is otherwise not possible
- newPref f useSophisticatedDiffMarking 1 Diff
- # A good idea, but can mess up window colours sometimes
- # (it's a bit of a hack)
- newPref f useFastWindowSwapping 1 Diff
- # Slows things down in that it has to scan through Alpha's list of marks
- # to find the correct positions for each window, but speeds things up
- # because it doesn't need to activate each window in turn. Try it and see
- # for yourself.
- newPref f useMarksDontBringToFront 1 Diff
- # Up/Down arrows both scroll the diff window and synchronise the viewed
- # portion of text in the document windows
- newPref f synchroniseMoveAndView 1 Diff Diff::bindUpDown
- # You'll probably want this; may slow things down a bit though
- newPref f workaroundAlphaColourBug 1 Diff
- # Default lines of context to generate when asking Diff to do its magic
- newPref var linesOfContext 3 Diff
- # Other diff flags you want to send (ignore whitespace etc)
- newPref var diffFlags { } Diff
- # If you've imported a diff file from a Unix system, this option allows
- # you to use it with Alpha too.
- newPref f convertSlashToColonInPaths 1 Diff
- # If you've imported a diff file from a different directory structure,
- # you may need to remove a given prefix so Alpha can find your files
- # correctly.
- newPref v removeFilePrefix "" Diff
-
- Menu -n $diffMenu -p Diff::menuProc -M Diff {
- "rerunDiff"
- "(-"
- "/<I<BpatchIntoLeftWindow"
- "/<I<BpatchIntoRightWindow"
- "(-"
- "cleanUpAndCloseWindows"
- "(-"
- "locateLeftWindow"
- "locateRightWindow"
- "locateLeftDir"
- "locateRightDir"
- "parseDiffWin"
- }
- Bind 0x7b <z> Diff::patchIntoLeftWindow Diff
- Bind 0x7c <z> Diff::patchIntoRightWindow Diff
-
- if {[info tclversion] < 8.0} {
- # Bind manually due to bug
- Bind 0x7b <oz> Diff::patchIntoLeftWindow Diff
- Bind 0x7c <oz> Diff::patchIntoRightWindow Diff
- }
- # do the rest
- Bind '\r' Diff::Select Diff
- Bind '\t' Diff::View Diff
- Bind Kpad. <c> Diff::Win
- Bind Enter {Diff::Down;Diff::Select} Diff
- Bind Kpad0 {Diff::Up;Diff::Select} Diff
-
- hook::register closeHook Diff::closing Diff
- hook::register openHook Diff::opening Diff
-
- proc Diff::bindUpDown {} {
- global DiffmodeVars
- if {$DiffmodeVars(synchroniseMoveAndView)} {
- catch {unBind down Diff::Down Diff}
- catch {unBind up Diff::Up Diff}
- Bind down {Diff::Down;Diff::View} Diff
- Bind up {Diff::Up;Diff::View} Diff
- } else {
- catch {unBind down {Diff::Down;Diff::View} Diff}
- catch {unBind up {Diff::Up;Diff::View} Diff}
- Bind down Diff::Down Diff
- Bind up Diff::Up Diff
- }
- }
-
- Diff::bindUpDown
-
- proc Diff::menuProc {menu item} {
- Diff::$item
- }
-
- proc Diff::locateLeftWindow {} {
- global Diff::1
- set Diff::1 [getfile "Select your left (old) file:"]
- Diff::Display Diff::1 1 0 1
- Diff::setMarksUp
- if {[info exists Diff::1]} {Diff::mark ${Diff::1} 1 ""}
- Diff::diffWinFront
- }
-
- proc Diff::locateRightWindow {} {
- global Diff::2
- set Diff::2 [getfile "Select your right (new) file:"]
- Diff::Display Diff::2 0 0 1
- Diff::setMarksUp
- if {[info exists Diff::2]} {Diff::mark ${Diff::2} 0 ""}
- Diff::diffWinFront
- }
-
- proc Diff::locateLeftDir {} {
- global Diff::leftDir
- set Diff::leftDir [get_directory "Select your left (old) directory:"]
- append Diff::leftDir :
- }
- proc Diff::locateRightDir {} {
- global Diff::rightDir
- set Diff::rightDir [get_directory "Select your right (new) directory:"]
- append Diff::rightDir :
- }
-
- proc Diff::rerunDiff {} {
- global diffDir Diff::1 Diff::2
- Diff::diffWinFront
- catch {set d1 ${Diff::1}}
- catch {set d2 ${Diff::2}}
- killWindow
- catch {set Diff::1 $d1}
- catch {set Diff::2 $d2}
- if {$diffDir} {
- Diff::execute 1 {* Directory Comparison *}
- } else {
- Diff::files
- }
- }
-
- proc Diff::cleanUpAndCloseWindows {} {
- global Diff::1 Diff::2 diffDir
- if {![catch {bringToFront ${Diff::1}}]} {
- removeAllMarks diff-*
- shrinkFull
- killWindow
- }
-
- if {![catch {bringToFront ${Diff::2}}]} {
- removeAllMarks diff-*
- shrinkFull
- killWindow
- }
- Diff::diffWinFront
- killWindow
- }
-
- proc Diff::closing {{name ""}} {
- global Diff::array Diff::Marked Diff::1 Diff::2
- foreach var [info globals Diff::array*] {
- global $var
- if {[array exists $var]} { unset $var }
- }
- catch {unset Diff::Marked}
- catch {unset Diff::1}
- catch {unset Diff::2}
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Diff::opening" --
- #
- # This procedure is called whenever we open a diff window, whether
- # a '.diff' file, or whether a window produced by this mode using
- # 'Diff::execute'. We parse its contents.
- # -------------------------------------------------------------------------
- ##
- proc Diff::opening {name} {
- global Diff::window DiffmodeVars Diff::leftDir Diff::rightDir
- set Diff::window $name
- set Diff::leftDir ""
- set Diff::rightDir ""
-
- if {$DiffmodeVars(useSophisticatedDiffMarking)} {
- Diff::parseDiffWin
- }
- }
-
- # ◊◊◊◊ Parsing diff information ◊◊◊◊ #
-
- proc Diff::parseDiffWin {} {
- Diff::diffWinFront
- global diffDir Diff::window
-
- set pos [minPos]
- while 1 {
- set res [search -s -n -f 1 -r 1 "^(diff.*|\[^- \n\r\]+)(\r|\n|\$)" $pos]
- if {$res != ""} {
- set pos [pos::math [lindex $res 0] + 1]
- # if we picked up a 'diff...' line in a context diff
- if {[lookAt $pos] == "i" && [lookAt [nextLineStart [lindex $res 0]]] == "*"} {
- continue
- }
- set t [getText [lindex $res 0] [pos::math [lindex $res 1] - 1]]
- if {[regexp {^\*+$} $t]} {
- set diffDir 1
- # check if the file has changed
- if {[string index [set tt [getText [prevLineStart $pos] $pos]] 0] != " " \
- && [lookAt [pos::math $pos - 3]] != "-" } {
- set to [lindex $tt 1]
- regexp " (.*)\t" $tt "" to
- set p [prevLineStart $pos]
- regexp " (.*)\t" [getText [prevLineStart $p] $p] from
- regsub -all "/" $from ":" from
- regsub -all "/" $to ":" to
- lappend got [list "diff" $from $to]
- }
- set from [lindex [eval getText [search -s -n -f 1 -r 1 {^\*\*\* [0-9]+,[0-9]+} $pos]] 1]
- set to [lindex [eval getText [search -s -n -f 1 -r 1 {^--- [0-9]+,[0-9]+} $pos]] 1]
- lappend got "$from $to"
- } else {
- lappend got $t
- }
- } else {
- break
- }
- }
- set Diff::window [win::Current]
- # now stored all diff items in the list 'got'
- if {[info exists got]} {Diff::storeMarks $got}
- Diff::diffWinFront
- global tileTop tileWidth tileHeight tileLeft
- set top [expr {$tileTop + $tileHeight - 178}]
- sizeWin ${Diff::window} [expr {$tileWidth - 6}] 178
- moveWin ${Diff::window} $tileLeft $top
-
- }
-
- proc Diff::storeMarks {diffs} {
- global Diff::1 Diff::2 Diff::array
- set suff ""
- foreach m $diffs {
- if {[regexp {^diff} $m]} {
- set suff "/[file tail [lindex $m end]]"
- global Diff::array${suff}
- continue
- }
- set Diff::array${suff}($m) ""
- }
- }
-
- proc Diff::setMarksUp {{suff ""}} {
- global Diff::array${suff}
- foreach m [array names Diff::array$suff] {
- set scanned [Diff::parseDiffString $m]
- if {[scan $scanned "%s %d %d %d %d" \
- char start1 end1 start2 end2] != 5} { error "Bad diff list!" }
- if {$scanned != ""} {
- set Diff::array${suff}($m) $scanned
- }
- }
- }
-
- proc Diff::mark {win left {suff ""}} {
- global Diff::array$suff DiffmodeVars
- if {$win != ""} {
- # Alpha somehow remembers the last mode in which it adjusts
- # the window and so forgets all the colours if we cheat the
- # mode switch.
- if {$DiffmodeVars(workaroundAlphaColourBug)} {
- bringToFront $win
- } else {
- Diff::BringToFront $win
- }
- # not strictly necessary, but cleaner
- removeAllMarks diff-*
- if {$left} {
- foreach m [array names Diff::array$suff] {
- scan [set Diff::array${suff}($m)] "%s %d %d" char start1 end1
- setNamedMark "diff-$m" $start1 $start1 $end1
- }
- } else {
- foreach m [array names Diff::array$suff] {
- scan [set Diff::array${suff}($m)] "%s %d %d %d %d" char start1 end1 start2 end2
- setNamedMark "diff-$m" $start2 $start2 $end2
- }
- }
- }
- }
-
- proc Diff::markUpWindow {diffs} {
- alertnote "Currently a little obsolete; shouldn't be called!"
- if {[info exists Diff::1]} {
- Diff::BringToFront ${Diff::1}
- # not strictly necessry, but cleaner
- removeAllMarks diff-*
- foreach m $diffs {
- scan [set Diff::array($m)] "%s %d %d" char start1 end1
- setNamedMark "diff-$m" $start1 $start1 $end1
- }
- }
- if {[info exists Diff::2]} {
- Diff::BringToFront ${Diff::2}
- # not strictly necessry, but cleaner
- removeAllMarks diff-*
- foreach m $diffs {
- scan [set Diff::array($m)] "%s %d %d %d %d" char start1 end1 start2 end2
- setNamedMark "diff-$m" $start2 $start2 $end2
- }
- }
-
- }
-
- proc Diff::parseDiffString {text} {
- global Diff::1 Diff::2
- if {![regexp {[acd]} $text char]} {
- # context sensitive
- set char "c"
- if {[scan $text "%d,%d %d,%d" one oned two twod] != 4} {
- return
- }
- } else {
- set res [split $text $char]
- if {![scan [lindex $res 0] "%d,%d" one oned]} return
- if {![scan [lindex $res 1] "%d,%d" two twod]} return
- if {![info exists oned]} { set oned $one }
- if {![info exists twod]} { set twod $two }
- }
-
- if {[info exists Diff::1]} {
- set res [list $char [rowColToPos -w ${Diff::1} $one 0]]
- if {$char != "a"} {
- lappend res [rowColToPos -w ${Diff::1} [expr {$oned + 1}] 0]
- } else {
- lappend res [rowColToPos -w ${Diff::1} $oned 1]
- }
- } else {
- set res [list $char -1 -1]
- }
-
- if {[info exists Diff::2]} {
- lappend res [rowColToPos -w ${Diff::2} $two 0]
- if {$char != "d"} {
- lappend res [rowColToPos -w ${Diff::2} [expr {$twod + 1}] 0]]
- } else {
- lappend res [rowColToPos -w ${Diff::2} $twod 1]
- }
- } else {
- lappend res -1 -1
- }
- return $res
- }
-
- proc Diff::parseDiffLine {text {is_pos 0}} {
- if {$is_pos} {
- set text [Diff::line $text]
- }
- return [Diff::parseDiffString $text]
- }
-
- proc Diff::line {pos {f ""}} {
- global diffDir Diff::window DiffmodeVars
- if {$diffDir} {
- if {$f != ""} {upvar $f files}
- if {[lookAt $pos] == "*" || [catch {search -s -f 0 -r 1 "^diff.*(\r|\n|\$)" $pos} res]} {
- set p $pos
- while 1 {
- set res [search -s -f 0 -r 1 "^\\*+(\r|\n|\$)" $p]
- set p [pos::math [lindex $res 0] - 2]
- if {[lookAt [lineStart $p]] != " " && [lookAt $p] != "-"} break
- }
- regexp " (.*)\t" [getText [lineStart $p] $p] "" to
- regexp " (.*)\t" [getText [prevLineStart $p] [lineStart $p]] "" from
- if {[set pr $DiffmodeVars(removeFilePrefix)] != ""} {
- regsub -all "/\./" $to "/" to
- if {[string first $pr $to] == 0} {
- set to [string range $to [string length $pr] end]
- }
- regsub -all "/\./" $from "/" from
- if {[string first $pr $from] == 0} {
- set from [string range $from [string length $pr] end]
- }
- }
- set files [list $from $to]
- set tfrom [lindex [eval getText [search -s -n -f 1 -r 1 {^\*\*\* [0-9]+,[0-9]+} [getPos]]] 1]
- set tto [lindex [eval getText [search -s -n -f 1 -r 1 {^--- [0-9]+,[0-9]+} [getPos]]] 1]
- set text "$tfrom $tto"
- } else {
- set llen [llength [set files [eval getText $res]]]
- set files [lrange $files [expr {$llen -2}] end]
- set text [getText [lineStart $pos] [pos::math [nextLineStart $pos] - 1]]
- }
- if {$DiffmodeVars(convertSlashToColonInPaths)} {
- regsub -all "/" $files ":" files
- }
- set f [lindex $files end]
- set suff "/[file tail $f]"
- } else {
- set suff ""
- set text [getText [lineStart $pos] [pos::math [nextLineStart $pos] - 1]]
- }
- return "${text}${suff}"
- }
-
- # ◊◊◊◊ Patching routines ◊◊◊◊ #
- proc Diff::patch {w1 w2 left} {
- global DiffmodeVars
- if {$DiffmodeVars(useSophisticatedDiffMarking)} {
- Diff::patchSophisticated $w1 $w2 $left
- } else {
- Diff::patchOld $w1 $w2 $left
- }
- }
- proc Diff::patchSophisticated {ww1 ww2 left} {
- upvar \#0 $ww1 w1
- upvar \#0 $ww2 w2
- set code [Diff::line [getPos]]
- regexp {([^/]+)(.*)} $code "" mark suff
- global Diff::array${suff}
- if {![info exists w1]} { dialog::errorAlert "No such window" }
- switch "[lindex [set Diff::array${suff}($mark)] 0]${left}" {
- "c1" -
- "c0" {
- if {[info exists w2]} {
- Diff::BringToFront ${w2}
- gotoMark "diff-$mark"
- set text [getSelect]
- } else {
- # we assume the line is selected in the diff-win
- if {$left} {
- set p [selEnd]
- set e [search -s -f 1 -r 1 {^---.*$} $p]
- set p [lindex $e 1]
- set e [search -s -f 1 -r 1 {^[^>]} $p]
- set text [getText $p [lindex $e 0]]
- regsub -all "\[\n\r\]> " $text "\r" text
- set text [string range $text 1 end]
- } else {
- set p [selEnd]
- set e [search -s -f 1 -r 1 {^---} $p]
- set text [getText $p [lindex $e 0]]
- regsub -all "\[\r\n\]< " $text "\r" text
- set text [string range $text 1 end]
- }
- }
- Diff::BringToFront ${w1}
- gotoMark "diff-$mark"
- replaceText [getPos] [selEnd] $text
- }
- "d1" -
- "a0" {
- Diff::BringToFront ${w1}
- gotoMark "diff-$mark"
- deleteText [getPos] [selEnd]
- }
- "a1" -
- "d0" {
- if {[info exists w2]} {
- Diff::BringToFront ${w2}
- gotoMark "diff-$mark"
- set text [getSelect]
- } else {
- # we assume the line is selected in the diff-win
- if {$left} {
- set p [selEnd]
- set e [search -s -f 1 -r 1 {^---.*$} $p]
- set p [lindex $e 1]
- set e [search -s -f 1 -r 1 {^[^>]} $p]
- set text [getText $p [lindex $e 0]]
- regsub -all "\[\n\r\]> " $text "\r" text
- set text [string range $text 1 end]
- } else {
- set p [selEnd]
- set e [search -s -f 1 -r 1 {^---} $p]
- set text [getText $p [lindex $e 0]]
- regsub -all "\[\n\r\]< " $text "\r" text
- set text [string range $text 1 end]
- }
- }
- Diff::BringToFront ${w1}
- gotoMark "diff-$mark"
- nextLine
- insertText -w ${w1} $text
- }
- }
- Diff::diffWinFront
- }
- proc Diff::patchOld {ww1 ww2 left} {
- upvar \#0 $ww1 w1
- upvar \#0 $ww2 w2
- set code [Diff::line [getPos]]
- if {[scan [Diff::parseDiffLine $code] "%s %d %d %d %d" \
- char start1 end1 start2 end2] != 5} { return }
-
- switch $char${left} {
- "c1" {
- set text [getText -w ${w2} $start2 $end2]
- bringToFront ${w1}
- replaceText $start1 $end1 $text
- }
- "d1" {
- bringToFront ${w1}
- deleteText $start1 $end1
- }
- "a1" {
- set text [getText -w ${w2} $start2 $end2]
- set p [nextLineStart $start1]
- # for some reason this single line won't work instead of the
- # next two!
- #select -w ${Diff::1} $p $p
- bringToFront ${w1}
- goto $p
- insertText -w ${w1} $text
- }
- "c0" {
- set text [getText -w ${w2} $start1 $end1]
- bringToFront ${w1}
- replaceText $start2 $end2 $text
- }
- "d0" {
- set text [getText -w ${w2} $start1 $end1]
- bringToFront ${w1}
- goto $start2
- nextLine
- insertText $text
- }
- "a0" {
- bringToFront ${w1}
- deleteText $start2 $end2
- }
- }
- message "Subsequent insertions will be screwed up"
- }
-
- # In the diff-window, 'c' = cut from left, replace with given lines,
- # 'd' = delete from left, 'a' = add to left.
- proc Diff::patchIntoLeftWindow {} {
- Diff::patch Diff::1 Diff::2 1
- }
-
- proc Diff::patchIntoRightWindow {} {
- Diff::patch Diff::2 Diff::1 0
- }
-
- # ◊◊◊◊ Main comparison routines ◊◊◊◊ #
-
- proc Diff::files {} {
- global Diff::1 Diff::2
- foreach f [list ${Diff::1} ${Diff::2}] {
- if {[lsearch [winNames -f] $f] >= 0} {
- getWinInfo -w $f arr
- if {$arr(dirty)} {
- bringToFront $f
- if {![dialog::yesno "Save this window?"]} { error "Cancel"}
- save
- }
- }
- }
- # make sure newer file is on the right
- if {[file::secondIsOlder ${Diff::1} ${Diff::2}]} {
- set d ${Diff::2}
- set Diff::2 ${Diff::1}
- set Diff::1 $d
- unset d
- }
- Diff::run
- }
-
- proc Diff::run {} {
- global Diff::handler Diff::handlers
- # call the registered procedure
- [set Diff::handlers([set Diff::handler])]
- }
-
- proc Diff::runInsideAlpha {} {
- global Diff::1 Diff::2
- Diff::Display Diff::1 1 0 1
- Diff::Display Diff::2 0 0 1
-
- Diff::execute
- }
-
- proc compare::directories {} {
- global Diff::1 Diff::2
-
- set Diff::1 [get_directory -p "Select 'old' dir 1:"]
- set Diff::2 [get_directory -p "Select 'new' dir 2:"]
-
- Diff::execute 1 {* Directory Comparison *}
- }
-
- proc compare::files {} {
- global Diff::1 Diff::2
-
- set Diff::1 [getfile "Select your 'old' file:"]
- set Diff::2 [getfile "Select your 'new' file:"]
-
- Diff::files
- }
-
- proc compare::windows {} {
- global tileHeight tileWidth tileTop tileLeft
- global Diff::1 Diff::2
-
- set wins [winNames -f]
- if {[llength $wins] < 2} { message "Need 2 windows"; return }
-
- set Diff::1 [lindex $wins 0]
- set Diff::2 [lindex $wins 1]
- Diff::files
- }
-
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Diff::execute" --
- #
- # Modification of the original to optionally return the diff
- # result, rather than opening it in a window
- #
- # Results:
- #
- # Returns 1 if the files are the same and 0 if they differ
- #
- # If storeResult is true, the result of the diff operation is stored
- # in the global Diff::result, rather than being opened in a window
- #
- # --Version--Author------------------Changes-------------------------------
- # 1.0 <keleher@cs.umd.edu> original
- # 1.1 <j-guyer@nwu.edu> optionally return diff result in a global
- # 1.2 <j-guyer@nwu.edu> flags set if files were open before compare
- # -------------------------------------------------------------------------
- ##
- proc Diff::execute {{isdir 0} {name {* File Comparison *}} {storeResult 0}} {
- global DiffmodeVars \
- Diff::1 Diff::2 win::Modes HOME diffDir Diff::result \
- Diff::1Open Diff::2Open \
- Diff::leftDir Diff::rightDir DiffSig
-
- set Diff::leftDir ""
- set Diff::rightDir ""
- set diffDir $isdir
-
- message "Launching 'GNU Diff'"
- set flags $DiffmodeVars(diffFlags)
- if {$DiffmodeVars(linesOfContext) != 0} {
- append flags " -C $DiffmodeVars(linesOfContext)"
- }
- message "Starting diff…"
- append flags " \"[stripNameCount ${Diff::1}]\" \"[stripNameCount ${Diff::2}]\""
- set dtext [app::runScript Diff "Diff application" "" 1 0 $flags]
- message "Starting diff…done"
-
- if {[lsearch [winNames -f] ${Diff::1}] >= 0} {
- set Diff::1Open 1
- } else {
- set Diff::1Open 0
- }
- if {[lsearch [winNames -f] ${Diff::2}] >= 0} {
- set Diff::2Open 1
- } else {
- set Diff::2Open 0
- }
-
- if {![string length $dtext]} {
- if {!$storeResult} {
- alertnote "No difference:\r${Diff::1}\r${Diff::2}"
- }
- return 0
- } else {
- # If requested, return the diff result in Diff::result,
- # rather than opening a diff window
- if {$storeResult} {
- set Diff::result $dtext
- } else {
- Diff::diffWindow $dtext $name
- }
- return 1
- }
- }
-
- proc Diff::displayAll {{name "* File Comparison *"}} {
- global Diff::1 Diff::2 Diff::result
-
- Diff::Display Diff::1 1 0 1
- Diff::Display Diff::2 0 0 1
- Diff::diffWindow ${Diff::result} $name
- }
-
- proc Diff::diffWindow {diffText {name {* File Comparison *}}} {
- global tileLeft tileTop tileWidth tileHeight
-
- set top [expr {$tileTop + $tileHeight - 178}]
- set n [new -n $name -g $tileLeft $top [expr {$tileWidth - 6}] 178 \
- -m Diff -info "\r$diffText\r"]
- select [minPos] [nextLineStart [minPos]]
- Diff::opening $n
- }
-
- # ◊◊◊◊ Moving around ◊◊◊◊ #
- proc Diff::Up {} {
- set res [search -s -f 0 -r 1 -- "^\[^- \n\r\]+(\r|\n|\$)" [pos::math [getPos] - 1]]
- set pos [lindex $res 0]
- select $pos [nextLineStart $pos]
- display $pos
- refresh
- }
-
- proc Diff::Down {} {
- set res [search -s -f 1 -r 1 -- "^\[^- \n\r\]+(\r|\n|\$)" [pos::math [getPos] + 1]]
- set pos [lindex $res 0]
- select $pos [nextLineStart $pos]
- display $pos
- refresh
- }
-
- proc Diff::Select {} {
- global Diff::1 Diff::2 diffDir
-
- set text [getText [lineStart [getPos]] [pos::math [nextLineStart [getPos]] - 1]]
-
- if {![regexp {[acd]} $text char]} return
- set res [split $text $char]
- if {![scan [lindex $res 0] "%d" one]} return
- if {![scan [lindex $res 1] "%d" two]} return
- if {$one == 1} {incr one}
- if {$two == 1} {incr two}
-
- if {$diffDir} {
- set res [search -s -f 0 -r 1 "^diff.*(\r|\n|\$)" [getPos]]
- set text [eval getText $res]
- set len [llength $text]
- set Diff::1 [lindex $text [expr {$len - 2}]]
- set Diff::2 [lindex $text [expr {$len - 1}]]
- }
- Diff::Display Diff::1 1 [expr {$one - 1}] $diffDir
- Diff::Display Diff::2 0 [expr {$two - 1}] $diffDir
-
- if {$diffDir} {
- catch {bringToFront ${Diff::window}}
- }
- }
-
- proc Diff::Display {name left {row 0} {check 0}} {
- upvar $name wname
- if {![info exists wname]} {
- if {$left} {
- message "Diff window for left doesn't exist"
- } else {
- message "Diff window for right doesn't exist"
- }
- return
- }
- if {$check} {
- set geo [Diff::Geo $left]
- set res [lsearch [winNames -f] "$wname"];
- if { $res < 0 } {
- set res [lsearch [winNames -f] "$wname <*>"];
- }
- if { $res < 0} {
- eval edit -g $geo [list $wname]
- set wname [win::Current]
- } else {
- set wname [lindex [winNames -f] $res]
- if {[getGeometry $wname] != $geo} {
- sizeWin $wname [lindex $geo 2] [lindex $geo 3]
- moveWin $wname [lindex $geo 0] [lindex $geo 1]
- }
- if {$res > 2} {
- bringToFront $wname
- }
- }
- }
- display -w $wname [rowColToPos -w $wname $row 0]
- }
-
- proc Diff::viewSophisticated {} {
- global Diff::1 Diff::2 diffDir DiffmodeVars Diff::Marked
- global Diff::leftDir Diff::rightDir
-
- set text [Diff::line [getPos] files]
-
- if {$diffDir} {
- set Diff::1 ${Diff::leftDir}[lindex $files 0]
- if {![file exists ${Diff::1}]} {
- if {${Diff::leftDir} == "" && ([set res [lsearch [winNames] "[file tail ${Diff::1}]*"]] != -1)} {
- set Diff::1 [lindex [winNames -f] $res]
- } else {
- unset Diff::1
- }
- } else {
- if {[set res [lsearch [winNames -f] "${Diff::1}*"]] != -1} {
- set Diff::1 [lindex [winNames -f] $res]
- }
- }
- set Diff::2 ${Diff::rightDir}[lindex $files 1]
- if {![file exists ${Diff::2}]} {
- if {${Diff::rightDir} == "" && ([set res [lsearch [winNames] "[file tail ${Diff::2}]*"]] != -1)} {
- set Diff::2 [lindex [winNames -f] $res]
- } else {
- unset Diff::2
- }
- } else {
- if {[set res [lsearch [winNames -f] "${Diff::2}*"]] != -1} {
- set Diff::2 [lindex [winNames -f] $res]
- }
- }
- }
- regexp {([^/]+)(.*)} $text "" mark suff
- if {![info exists "Diff::Marked($suff)"]} {
- Diff::Display Diff::1 1 0 1
- Diff::Display Diff::2 0 0 1
- Diff::setMarksUp $suff
- if {[info exists Diff::1]} {
- Diff::mark ${Diff::1} 1 $suff
- set Diff::Marked($suff) 1
- }
- if {[info exists Diff::2]} {
- Diff::mark ${Diff::2} 0 $suff
- set Diff::Marked($suff) 1
- }
- Diff::diffWinFront
- }
- set text $mark
-
- if {$DiffmodeVars(useMarksDontBringToFront)} {
- if {![catch {mark::getRange diff-$text ${Diff::1}} range]} {
- set beg [lindex $range 0]
- set end [lindex $range 2]
- display -w ${Diff::1} [expr \
- {[pos::compare $beg > [minPos]] \
- ? [pos::math $beg - 1] : $beg}]
- select -w ${Diff::1} $beg $end
- if {[pos::compare $beg > [minPos]]} {
- set beg [pos::math $beg - 1]
- }
- #display -w ${Diff::1} $beg
- #refresh ${Diff::1}
- }
-
- if {![catch {mark::getRange diff-$text ${Diff::2}} range]} {
- set beg [lindex $range 0]
- set end [lindex $range 2]
- display -w ${Diff::2} [expr \
- {[pos::compare $beg > [minPos]] \
- ? [pos::math $beg - 1] : $beg}]
- select -w ${Diff::2} $beg $end
- if {[pos::compare $beg > [minPos]]} {
- set beg [pos::math $beg - 1]
- }
- #display -w ${Diff::2} $beg
- #refresh ${Diff::2}
- }
- # we need this line because of an Alpha visual bug.
- # Alpha will often draw the text in the wrong window when we
- # hit 'down'. It does correct itself, but it looks silly.
- Diff::diffWinFront
- } else {
- if {![catch {Diff::BringToFront ${Diff::1}}]} {
- gotoMark "diff-$text"
- }
- if {![catch {Diff::BringToFront ${Diff::2}}]} {
- gotoMark "diff-$text"
- }
- Diff::diffWinFront
- }
- }
- proc Diff::viewOld {} {
- global Diff::1 Diff::2 diffDir
-
- set text [Diff::line [getPos]]
- if {![regexp {[acd]} $text char]} return
- set res [split $text $char]
- if {![scan [lindex $res 0] "%d,%d" one oned]} return
- if {![scan [lindex $res 1] "%d,%d" two twod]} return
- set on $one
- set tw $two
- if {$on == 1} {incr on}
- if {$tw == 1} {incr tw}
- if {![info exists oned]} {set oned $one}
- if {![info exists twod]} {set twod $two}
-
- if {$diffDir} {
- set res [search -s -f 0 -r 1 "^diff.*(\r|\n|\$)" [getPos]]
- set text [eval getText $res]
- set Diff::1 [lindex $text 1]
- set Diff::2 [lindex $text 2]
- }
- Diff::Sel Diff::1 [expr {$on - 1}] $one $oned 1
- Diff::Sel Diff::2 [expr {$tw - 1}] $two $twod 0
- set wins [lremove [lrange [winNames -f] 0 2] ${Diff::1} ${Diff::2}]
- set wins [lremove -glob $wins *Comparison*]
- if {$wins != ""} {
- bringToFront ${Diff::1}
- bringToFront ${Diff::2}
- }
- Diff::diffWinFront
- }
-
- proc Diff::View {} {
- global DiffmodeVars
- if {$DiffmodeVars(useSophisticatedDiffMarking)} {
- Diff::viewSophisticated
- } else {
- Diff::viewOld
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Diff::Sel" --
- #
- # This handles a name either with or without trailing '<n>' and fixes
- # the given name if it isn't right.
- # -------------------------------------------------------------------------
- ##
- proc Diff::Sel {wnamev ro row rowd left} {
- global diffDir
- upvar $wnamev wname
- if {$diffDir} {
- set geo [Diff::Geo $left]
- if {[set res [lsearch [winNames -f] "$wname*"]] < 0} {
- eval edit -g $geo [list $wname]
- set wname [win::Current]
- } else {
- set wname [lindex [winNames -f] $res]
- if {[getGeometry $wname] != $geo} {
- sizeWin $wname [lindex $geo 2] [lindex $geo 3]
- moveWin $wname [lindex $geo 0] [lindex $geo 1]
- }
- }
- }
- display -w $wname [rowColToPos -w $wname $ro 0]
- select -w $wname [rowColToPos -w $wname $row 0] \
- [rowColToPos -w $wname [expr {$rowd + 1}] 0]
- }
-
- # ◊◊◊◊ Utilities ◊◊◊◊ #
-
- proc Diff::Win {} {
- global win::Modes
- set files [winNames -f]
- set len [llength $files]
- for {set i 0} {$i < $len} {incr i} {
- if {[set win::Modes([lindex [winNames -f] $i])] == "Diff"} {
- bringToFront [lindex [winNames] $i]
- return
- }
- }
- beep
- message "No Diff window."
- }
-
- proc Diff::Geo {left} {
- global tileWidth tileHeight tileTop tileLeft
-
- set margin 4
- set width [expr {($tileWidth - $margin)/2}]
- set height [expr {$tileHeight - 200}]
- set hor $tileLeft
-
- if {!$left} {incr hor [expr {$width+$margin}]}
-
- return [list $hor $tileTop $width $height]
- }
-
- proc Diff::diffWinFront {} {
- global Diff::window
- catch {bringToFront ${Diff::window}}
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "Diff::BringToFront" --
- #
- # Hack to make it quicker to switch between windows. We often want
- # the 'Diff' window to be in the front all the time, but have to
- # bring others to the front temporarily for manipulation. This proc
- # brings a different window to the front more quickly by avoiding
- # all mode-changing code. Of course you should only call this proc
- # when you will _very_ soon bring a different window to the front.
- # -------------------------------------------------------------------------
- ##
- proc Diff::BringToFront {w} {
- global win::Modes DiffmodeVars
- if {$DiffmodeVars(useFastWindowSwapping)} {
- set oldm [set win::Modes($w)]
- set win::Modes($w) Diff
- if {[catch {bringToFront $w}]} {
- unset win::Modes($w)
- beep
- error "no such win"
- } else {
- set win::Modes($w) $oldm
- }
- } else {
- bringToFront $w
- }
- }
-